🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / service / src / androidMain / kotlin / org / meshtastic / core / service / AndroidNotificationManager.kt
Displaying Raw • Download
core/service/src/androidMain/kotlin/org/meshtastic/core/service/AndroidNotificationManager.kt d102ca262a5e22d3fbad6b994a004212ef18e750 (d102ca26) Text, 9.09 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.service
Tff7b72import T7ee787android.app.NotificationChannel
Tff7b72import T7ee787android.app.PendingIntent
Tff7b72import T7ee787android.app.TaskStackBuilder
Tff7b72import T7ee787android.content.Context
Tff7b72import T7ee787android.content.Intent
Tff7b72import T7ee787android.os.Build
Tff7b72import T7ee787androidx.core.app.NotificationCompat
Tff7b72import T7ee787androidx.core.app.NotificationManagerCompat
Tff7b72import T7ee787androidx.core.content.getSystemService
Tff7b72import T7ee787androidx.core.net.toUri
Tff7b72import T7ee787kotlinx.coroutines.sync.Mutex
Tff7b72import T7ee787kotlinx.coroutines.sync.withLock
Tff7b72import T7ee787org.koin.core.annotation.Single
Tff7b72import T7ee787org.meshtastic.core.repository.Notification
Tff7b72import T7ee787org.meshtastic.core.repository.NotificationManager
Tff7b72import T7ee787org.meshtastic.core.resources.R.drawable
Tff7b72import T7ee787org.meshtastic.core.resources.Res
Tff7b72import T7ee787org.meshtastic.core.resources.getStringSuspend
Tff7b72import T7ee787org.meshtastic.core.resources.meshtastic_alerts_notifications
Tff7b72import T7ee787org.meshtastic.core.resources.meshtastic_low_battery_notifications
Tff7b72import T7ee787org.meshtastic.core.resources.meshtastic_mesh_beacon_notifications
Tff7b72import T7ee787org.meshtastic.core.resources.meshtastic_messages_notifications
Tff7b72import T7ee787org.meshtastic.core.resources.meshtastic_new_nodes_notifications
Tff7b72import T7ee787org.meshtastic.core.resources.meshtastic_service_notifications
Tff7b72import T7ee787android.app.NotificationManager Tff7b72as Te6edf3SystemNotificationManager
Tf0883e@Single
Tff7b72class T56d364AndroidNotificationManagerTb4b4b4(Tff7b72private Tff7b72val Te6edf3contextTb4b4b4: Te6edf3ContextTb4b4b4) Tb4b4b4: Te6edf3NotificationManager Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3notificationManager Tff7b72=
Te6edf3checkNotNullTb4b4b4(Te6edf3contextTb4b4b4.Te6edf3getSystemServiceTff7b72<Te6edf3SystemNotificationManagerTff7b72>Tb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffNotificationManager not foundTa5d6ff" Tb4b4b4}
Tff7b72private Tff7b72data Tff7b72class T56d364ChannelConfigTb4b4b4(Tff7b72val Te6edf3idTb4b4b4: Tffa657StringTb4b4b4, Tff7b72val Te6edf3importanceTb4b4b4: Tffa657IntTb4b4b4)
T8b949e/**
* Tracks whether notification channels have been created.
*
* Channels are **not** created in the constructor because this singleton is instantiated by Koin during
* [org.meshtastic.core.service.MeshService.onCreate] on the main thread, and channel names come from string
* resources. Instead, channels are lazily ensured before the first [dispatch] call. Note that
* [MeshNotificationManagerImpl.initChannels] already creates a superset of these channels when the orchestrator
* starts, so this lazy path is only a safety net for notifications dispatched before orchestrator initialization.
*
* The mutex is load-bearing: resolving the names suspends, so without it two concurrent [dispatch] calls could both
* pass the flag check and post before the channels exist.
*/
Tff7b72private Tff7b72var Te6edf3channelsInitialized Tff7b72= Tff7b72false
Tff7b72private Tff7b72val Te6edf3channelInitMutex Tff7b72= Te6edf3MutexTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffensureChannelsInitializedTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3channelInitMutexTb4b4b4.Te6edf3withLock Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3channelsInitializedTb4b4b4) Tff7b72returnTf0883e@withLock
Te6edf3channelsInitialized Tff7b72= Tff7b72true
Tff7b72if Tb4b4b4(Te6edf3BuildTb4b4b4.Te6edf3VERSIONTb4b4b4.Te6edf3SDK_INT Tff7b72>Tff7b72= Te6edf3BuildTb4b4b4.Te6edf3VERSION_CODESTb4b4b4.Te6edf3OTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3channels Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3createChannelTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3MessageTb4b4b4, Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3meshtastic_messages_notificationsTb4b4b4)Tb4b4b4,
Te6edf3createChannelTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3NodeEventTb4b4b4, Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3meshtastic_new_nodes_notificationsTb4b4b4)Tb4b4b4,
Te6edf3createChannelTb4b4b4(
Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3MeshBeaconTb4b4b4,
Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3meshtastic_mesh_beacon_notificationsTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3createChannelTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3BatteryTb4b4b4, Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3meshtastic_low_battery_notificationsTb4b4b4)Tb4b4b4,
Te6edf3createChannelTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3AlertTb4b4b4, Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3meshtastic_alerts_notificationsTb4b4b4)Tb4b4b4,
Te6edf3createChannelTb4b4b4(Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3ServiceTb4b4b4, Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3meshtastic_service_notificationsTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3notificationManagerTb4b4b4.Te6edf3createNotificationChannelsTb4b4b4(Te6edf3channelsTb4b4b4)
Te6edf3notificationManagerTb4b4b4.Te6edf3removeLegacyCategoryChannelsTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffcreateChannelTb4b4b4(
Te6edf3categoryTb4b4b4: Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4,
Te6edf3nameResTb4b4b4: Te6edf3orgTb4b4b4.Te6edf3jetbrainsTb4b4b4.Te6edf3composeTb4b4b4.Te6edf3resourcesTb4b4b4.Te6edf3StringResourceTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3NotificationChannel Tb4b4b4{
Tff7b72val Te6edf3channelConfig Tff7b72= Te6edf3categoryTb4b4b4.Te6edf3channelConfigTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3NotificationChannelTb4b4b4(Te6edf3channelConfigTb4b4b4.Te6edf3idTb4b4b4, Te6edf3getStringSuspendTb4b4b4(Te6edf3nameResTb4b4b4)Tb4b4b4, Te6edf3channelConfigTb4b4b4.Te6edf3importanceTb4b4b4)
Tb4b4b4}
T8b949e// Keep category-to-channel mapping aligned with MeshNotificationManagerImpl.NotificationType IDs.
Tff7b72private Tff7b72fun Te6edf3NotificationTb4b4b4.Td2a8ffCategoryTb4b4b4.Te6edf3channelConfigTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3ChannelConfig Tff7b72= Tff7b72when Tb4b4b4(Tff7b72thisTb4b4b4) Tb4b4b4{
Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3Message Tff7b72-Tff7b72>
Te6edf3ChannelConfigTb4b4b4(
Te6edf3id Tff7b72= Te6edf3NotificationChannelsTb4b4b4.Te6edf3MESSAGESTb4b4b4,
Te6edf3importance Tff7b72= Te6edf3SystemNotificationManagerTb4b4b4.Te6edf3IMPORTANCE_HIGHTb4b4b4,
Tb4b4b4)
Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3NodeEvent Tff7b72-Tff7b72>
Te6edf3ChannelConfigTb4b4b4(
Te6edf3id Tff7b72= Te6edf3NotificationChannelsTb4b4b4.Te6edf3NEW_NODESTb4b4b4,
Te6edf3importance Tff7b72= Te6edf3SystemNotificationManagerTb4b4b4.Te6edf3IMPORTANCE_DEFAULTTb4b4b4,
Tb4b4b4)
Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3MeshBeacon Tff7b72-Tff7b72>
Te6edf3ChannelConfigTb4b4b4(
Te6edf3id Tff7b72= Te6edf3NotificationChannelsTb4b4b4.Te6edf3MESH_BEACONTb4b4b4,
Te6edf3importance Tff7b72= Te6edf3SystemNotificationManagerTb4b4b4.Te6edf3IMPORTANCE_LOWTb4b4b4,
Tb4b4b4)
Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3Battery Tff7b72-Tff7b72>
Te6edf3ChannelConfigTb4b4b4(
Te6edf3id Tff7b72= Te6edf3NotificationChannelsTb4b4b4.Te6edf3LOW_BATTERYTb4b4b4,
Te6edf3importance Tff7b72= Te6edf3SystemNotificationManagerTb4b4b4.Te6edf3IMPORTANCE_DEFAULTTb4b4b4,
Tb4b4b4)
Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3Alert Tff7b72-Tff7b72>
Te6edf3ChannelConfigTb4b4b4(Te6edf3id Tff7b72= Te6edf3NotificationChannelsTb4b4b4.Te6edf3ALERTSTb4b4b4, Te6edf3importance Tff7b72= Te6edf3SystemNotificationManagerTb4b4b4.Te6edf3IMPORTANCE_HIGHTb4b4b4)
Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3Service Tff7b72-Tff7b72>
Te6edf3ChannelConfigTb4b4b4(Te6edf3id Tff7b72= Te6edf3NotificationChannelsTb4b4b4.Te6edf3SERVICETb4b4b4, Te6edf3importance Tff7b72= Te6edf3SystemNotificationManagerTb4b4b4.Te6edf3IMPORTANCE_MINTb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffdispatchTb4b4b4(Te6edf3notificationTb4b4b4: Te6edf3NotificationTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Te6edf3ensureChannelsInitializedTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3channelId Tff7b72= Te6edf3notificationTb4b4b4.Te6edf3categoryTb4b4b4.Te6edf3channelConfigTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3id
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3canPostNotificationsTb4b4b4(Te6edf3channelIdTb4b4b4)Tb4b4b4) Tff7b72return Tff7b72false
Tff7b72val Te6edf3id Tff7b72= Te6edf3notificationTb4b4b4.Te6edf3id Tff7b72?: Te6edf3notificationTb4b4b4.Te6edf3hashCodeTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3builder Tff7b72=
Te6edf3NotificationCompatTb4b4b4.Te6edf3BuilderTb4b4b4(Te6edf3contextTb4b4b4, Te6edf3channelIdTb4b4b4)
Tb4b4b4.Te6edf3setContentTitleTb4b4b4(Te6edf3notificationTb4b4b4.Te6edf3titleTb4b4b4)
Tb4b4b4.Te6edf3setContentTextTb4b4b4(Te6edf3notificationTb4b4b4.Te6edf3messageTb4b4b4)
Tb4b4b4.Te6edf3setSmallIconTb4b4b4(Te6edf3drawableTb4b4b4.Te6edf3meshtastic_ic_notificationTb4b4b4)
Tb4b4b4.Te6edf3setAutoCancelTb4b4b4(Tff7b72trueTb4b4b4)
Tb4b4b4.Te6edf3setSilentTb4b4b4(Te6edf3notificationTb4b4b4.Te6edf3isSilentTb4b4b4)
Te6edf3notificationTb4b4b4.Te6edf3groupTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3builderTb4b4b4.Te6edf3setGroupTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3notificationTb4b4b4.Te6edf3type Tff7b72=Tff7b72= Te6edf3NotificationTb4b4b4.Te6edf3TypeTb4b4b4.Te6edf3ErrorTb4b4b4) Tb4b4b4{
Te6edf3builderTb4b4b4.Te6edf3setPriorityTb4b4b4(Te6edf3NotificationCompatTb4b4b4.Te6edf3PRIORITY_HIGHTb4b4b4)
Tb4b4b4}
Te6edf3notificationTb4b4b4.Te6edf3deepLinkUriTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3uri Tff7b72-Tff7b72> Te6edf3builderTb4b4b4.Te6edf3setContentIntentTb4b4b4(Te6edf3createDeepLinkPendingIntentTb4b4b4(Te6edf3uriTb4b4b4, Te6edf3idTb4b4b4)Tb4b4b4) Tb4b4b4}
Tff7b72return Tff7b72try Tb4b4b4{
Te6edf3notificationManagerTb4b4b4.Te6edf3notifyTb4b4b4(Te6edf3idTb4b4b4, Te6edf3builderTb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72true
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3_Tb4b4b4: Te6edf3SecurityExceptionTb4b4b4) Tb4b4b4{
Tff7b72false
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffcanPostNotificationsTb4b4b4(Te6edf3channelIdTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3NotificationManagerCompatTb4b4b4.Te6edf3fromTb4b4b4(Te6edf3contextTb4b4b4)Tb4b4b4.Te6edf3areNotificationsEnabledTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72&
Tb4b4b4(
Te6edf3BuildTb4b4b4.Te6edf3VERSIONTb4b4b4.Te6edf3SDK_INT Tff7b72< Te6edf3BuildTb4b4b4.Te6edf3VERSION_CODESTb4b4b4.Te6edf3O Tff7b72|Tff7b72|
Te6edf3notificationManagerTb4b4b4.Te6edf3getNotificationChannelTb4b4b4(Te6edf3channelIdTb4b4b4)Tff7b72?.Te6edf3importance Tff7b72!Tff7b72=
Te6edf3SystemNotificationManagerTb4b4b4.Te6edf3IMPORTANCE_NONE
Tb4b4b4)
T8b949e/**
* Builds a [PendingIntent] that launches [MainActivity] with the given deep-link URI as [Intent.ACTION_VIEW], so
* the existing deep-link plumbing (`UIViewModel.handleDeepLink` → `DeepLinkRouter` → `MultiBackstack`) can
* synthesize the proper backstack and surface the target screen.
*
* Uses [Class.forName] to avoid pulling the `:androidApp` module into `:core:service` as a Gradle dep.
*/
Tff7b72private Tff7b72fun Td2a8ffcreateDeepLinkPendingIntentTb4b4b4(Te6edf3uriTb4b4b4: Tffa657StringTb4b4b4, Te6edf3requestCodeTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3PendingIntent Tb4b4b4{
Tff7b72val Te6edf3deepLinkIntent Tff7b72=
Te6edf3IntentTb4b4b4(Te6edf3IntentTb4b4b4.Te6edf3ACTION_VIEWTb4b4b4, Te6edf3uriTb4b4b4.Te6edf3toUriTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3contextTb4b4b4, Te6edf3ClassTb4b4b4.Te6edf3forNameTb4b4b4(Te6edf3MAIN_ACTIVITY_CLASSTb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3apply Tb4b4b4{
Te6edf3flags Tff7b72= Te6edf3IntentTb4b4b4.Te6edf3FLAG_ACTIVITY_SINGLE_TOP
Tb4b4b4}
Tff7b72return Te6edf3TaskStackBuilderTb4b4b4.Te6edf3createTb4b4b4(Te6edf3contextTb4b4b4)Tb4b4b4.Te6edf3run Tb4b4b4{
Te6edf3addNextIntentWithParentStackTb4b4b4(Te6edf3deepLinkIntentTb4b4b4)
Te6edf3getPendingIntentTb4b4b4(Te6edf3requestCodeTb4b4b4, Te6edf3PendingIntentTb4b4b4.Te6edf3FLAG_IMMUTABLE Te6edf3or Te6edf3PendingIntentTb4b4b4.Te6edf3FLAG_UPDATE_CURRENTTb4b4b4)Tff7b72!!
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffcancelTb4b4b4(Te6edf3idTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3notificationManagerTb4b4b4.Te6edf3cancelTb4b4b4(Te6edf3idTb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffcancelAllTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3notificationManagerTb4b4b4.Te6edf3cancelAllTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72companion Tff7b72object Tb4b4b4{
T8b949e/**
* Fully-qualified name of the host activity that handles `meshtastic://` deep-link intents. Kept as a string to
* avoid creating a module dependency from `:core:service` back onto `:androidApp`.
*/
Tff7b72const Tff7b72val Te6edf3MAIN_ACTIVITY_CLASS Tff7b72= Ta5d6ff"Ta5d6fforg.meshtastic.app.MainActivityTa5d6ff"
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.06s